import java.util.Observable;
import java.util.Observer;
import java.util.Random;


public class Fantasma extends FantasmaStateMachine implements Observer {

	protected Posicion posicionPersecucion;
	protected Posicion posicionEscape;
	protected Direccion dirPersecucion;
	protected Direccion dirEscape;
	protected Direccion dirActual;
	protected Direccion dirInicial;
	
	public Direccion getDirInicial() {
		return dirInicial;
	}

	public void setDirInicial(Direccion dirInicial) {
		this.dirInicial = dirInicial;
	}


	protected int ira;
	static protected int N = 2;

	private Cronometro cronometro;

	public Cronometro getCronometro() {
		return cronometro;
	}

	public void setCronometro(Cronometro cronometro) {
		this.cronometro = cronometro;
	}

	public Fantasma(int segundosPresa, int segundosMuerto, Posicion actual) {
		super(new CazandoTranquilo(), actual);
		cronometro = new Cronometro(segundosPresa, segundosMuerto);
		cronometro.addObserver(this);
	}

	public Fantasma(int segundosPresa, int segundosMuerto, State initialState,
			Posicion actual) {
		super(initialState, actual);
		cronometro = new Cronometro(segundosPresa, segundosMuerto);
		cronometro.addObserver(this);
	}
	
	public void update(Observable arg0, Object arg1) {

		if (!cronometro.getRelojPresa().loPararon()) {
			System.out.println("volvieron a cazar");
			this.cambiarEstadoAnterior();
			cronometro.setRelojPresa(new Reloj(cronometro, cronometro
					.getSegundosPresa()));
		} else if (!cronometro.getRelojMuerto().loPararon()) {
			System.out.println("revivio fantasma");
			this.cambiarEstadoSiguiente(Evento.cazar);
			cronometro.setRelojMuerto(new Reloj(cronometro, cronometro
					.getSegundosMuerto()));
			cronometro.setRelojPresa(new Reloj(cronometro, cronometro
					.getSegundosPresa()));
		}

	}


	protected void moverSinVer() {
		 if (Config.debug) System.out.println("no lo ve");
		calcularPosicionesAleatorias();
		posicionActual = this.getCurrentState().mover((Fantasma) this);
		dirActual = this.getCurrentState().elejirDireccion((Fantasma) this);
	}

	protected void moverViendo(Posicion posPacman) {
		if (Config.debug) System.out.println("lo ve");
		calcularPosicionesProximas(posPacman);
		posicionActual = this.getCurrentState().mover((Fantasma) this);
		dirActual = this.getCurrentState().elejirDireccion((Fantasma) this);
	}

	public void mover(Posicion posPacman) {
		if (this.posicionActual.esCanal()) {
			if (Config.debug) System.out.println("es canal");
			this.posicionPersecucion = this.seguirDerechoORetroceder();
			this.posicionEscape = this.posicionPersecucion;
			posicionActual = this.getCurrentState().mover((Fantasma) this);
			dirActual = this.getCurrentState().elejirDireccion((Fantasma) this);
		}else{
		if (this.posicionActual.esBifurcacion()) {
			if (Config.debug) System.out.println("es bifurcacion");
			if(!loVe(posPacman)){
				moverSinVer();
			}
			else{
				moverViendo(posPacman);
			}
		}
		}

	}

	public boolean loVe(Posicion posPacman) {
		
		int distX = this.posicionActual.getX() - posPacman.getX();
		if (distX < 0)
			distX *= -1;
		int distY = this.posicionActual.getY() - posPacman.getY(); 
		if (distY < 0)
			distY *= -1;

		if ((distX < ira) && (distY < ira)) {
			return true;
		}
		return false;
	}

	protected void calcularPosicionesAleatorias() {
		Posicion aux = null;
		Direccion dir = null;
		boolean esIgual = true;
		Random rand = new Random();
		int x = 0;
		int cont = 0;

		if (dirActual == null) {
			while (esIgual) {
				x = rand.nextInt(4);
				dir = Direccion.values()[x];
				aux = posicionActual.adjacente(dir);
				if ((posicionActual.getX() != aux.getX())
						|| (posicionActual.getY() != aux.getY())) {
					dirPersecucion = dir;
					dirEscape = dir;
					esIgual = false;
				}

			}
		} else {
			while (esIgual) {

				cont++;
				x = rand.nextInt(4);
				dir = Direccion.values()[x];
				aux = posicionActual.adjacente(dir);
				if (((posicionActual.getX() != aux.getX()) || (posicionActual
						.getY() != aux.getY()))
						&& dir != Direccion.contrario(dirActual)) {
					dirPersecucion = dir;
					dirEscape = dir;
					esIgual = false;

				}
				if (cont == 40) {
					dirPersecucion = Direccion.contrario(dirActual);
					dirEscape = Direccion.contrario(dirActual);
					esIgual = false;
					aux = posicionActual.adjacente(Direccion.contrario(dirActual));
				}
			}

		}
		posicionEscape = aux;
		posicionPersecucion = aux;

	}

	private Posicion seguirDerechoORetroceder() {
		Posicion posActual = this.posicionActual;
		Posicion posAdyacente = this.posicionActual.adjacente(dirActual);
		Direccion dir = null;
		if (posActual.Equals(posAdyacente)) {
			if (Config.debug) System.out.println("va para atras");
			dir = Direccion.contrario(dirActual);
			this.dirEscape = dir;
			this.dirPersecucion = dir;
			return this.posicionActual.adjacente(dir);
		}
		
		this.dirEscape = dirActual;
		this.dirPersecucion = dirActual;
		return posAdyacente;
	}

	protected void calcularPosicionesProximas(Posicion posPacman) {
/*falla en los casos que las opciones no son encontradas entonces a veces elije lugares no mal, pero tiene opciones mejores
 * */	
		Posicion posActual = this.posicionActual;
		boolean encaminado = false;
		boolean encontrado = false;
		boolean encontrado2 = false;
		int suma = 0;
		int suma2 = 0;
		int total = 10000;
		int total2 = 0;

		int distX = this.posicionActual.getX() - posPacman.getX();
		if (distX < 0)
			distX *= -1;
		int distY = this.posicionActual.getY() - posPacman.getY();
		if (distY < 0)
			distY *= -1;
	
		Posicion auxPersecucion = null;
		for (int k = 0; k < 4; k++) {
			auxPersecucion = posicionActual
					.adjacente(Direccion.values()[k]);
			int nuevaDX = auxPersecucion.getX() - posPacman.getX();
			if (nuevaDX < 0)
				nuevaDX *= -1;
			int nuevaDY = auxPersecucion.getY() - posPacman.getY();
			if (nuevaDY < 0)
				nuevaDY *= -1;
			if (Direccion.values()[k] != Direccion.contrario(dirActual) && !this.posicionActual.Equals(auxPersecucion)) {
				encaminado = true;
			} else {
				encaminado = false;
			}			
			if (encaminado == true) {
				suma = nuevaDX + nuevaDY;
				if ((suma) <= (total)) {
					total = suma;
					this.dirPersecucion = Direccion.values()[k];
					encontrado = true;

				}
				if ((suma) >= (total2))  {
					total2 = suma;
					this.dirEscape = Direccion.values()[k];
					encontrado2 = true;
				}
				
				
				
			}

		}

			if (Config.debug) System.out.println(" dir final escape " + this.dirEscape);
			this.posicionEscape = posicionActual.adjacente(this.dirEscape);
			if (Config.debug) System.out.println(" pos escape " + this.posicionEscape.getX()
					+ " " + this.posicionEscape.getY());

			if (Config.debug) System.out.println(" dir final persec" + this.dirPersecucion);
			this.posicionPersecucion = posicionActual
					.adjacente(this.dirPersecucion);
			if (Config.debug) System.out.println(" pos perserc "
					+ this.posicionPersecucion.getX() + " "
					+ this.posicionPersecucion.getY());

	}
		
		@Override
		public void incrementarVision() {
			this.ira+=this.getCurrentState().incrementarVision();
		}

		
		public void setDireccionActual(Direccion direccion) {
			this.dirActual = direccion;
		}
		
		

}
	
	

